#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <numeric>
#include <cstdlib>
#include <string>
#include <sstream>
#include <fstream>
#include <iterator>
#include <ctime>

// #include "rpsrandom.h"
#include "rpssequence.h"
#include "rpstrain.h"


bool inBounds(double value, double low, double high) {
	if((value > low) && (value < high)){
		return true;
	} else return false;
}


//We want our functions to have an output as 0, 1, or 2. Inputs can be the past data
int temporary(){ //temporary function to go only rock
	return 0;
}

//Initialize random choice function
// int randomRPS();
int sequenceRPS(int prevmove);
std::pair<int, double> trainRPS(std::string pattern);

std::string showrps(int &move) { //saves some lines
	if (move==0) {
		return "R";
	} else if (move==1) {
		return "P";
	} else if (move==2) {
		return "S";
	}
}

//to do: have two computers play each other

int main(int argc, char** argv) {
	std::string input;
	bool letsplay=1; //keep playing until user quits
	std::vector<int> wtl (3,0); //win-tie-loss record. Don't play more than 2^31 times
	int pmove; //player's move. Rock is 0, Paper is 1, Scissors is 2.
	int cmove; //computer's move.
	int prevmove=0; //initialize player's previous move to 0;
	int streak=0; //for trashtalking

	//////////////////////////////////////////////////////
	// Algorithm selection--random and sequence options
	// used for testing.
	// Training algorithm will be used by default
	//////////////////////////////////////////////////////
	int algo=3;
	// std::cout << "Choose Algorithm: 1 for random, 2 for sequence, 3 for training" << std::endl;
	// std::cin >> algo;
	// std::cout << std::endl;

	int movecount=1;
	std::string moveseq;
	std::vector<double> rxn;
	int lossstreak=0;
	
	while (letsplay) {
		
		//////////////////////////////////////////////////////
		// Get user input and clock reaction time
		// Compute running average of reaction time for use
		//  in training algorithm
		//////////////////////////////////////////////////////
		std::cout << std::endl << "q to quit, r, p, or s to play" << std::endl;
		
		std::time_t start=time(0);
		
		getline(std::cin, input);
		
		std::time_t end=time(0);
		
		double time=std::difftime(end, start)*1000.0;
		rxn.push_back(time);
		
		double rxnsum = std::accumulate(rxn.begin(), rxn.end(), 0.0);
		double rxnmean = rxnsum / rxn.size();
		
		if (input == "q" or input =="Q") { //to quit
			letsplay=0;
      
		if (wtl[0]+wtl[1]+wtl[2]==0) {std::cout <<"Quitting before we get to play?!" <<std::endl;}   
		else if (wtl[0]>wtl[2]) {std::cout << "You got lucky! I'll get you next time!" <<std::endl;}
		else if (wtl[0]<wtl[2]) {std::cout << "Looks like I had the better strategy!" <<std::endl;}
		else {std::cout << "Let's play again sometime!" << std::endl;}
         
			//want to add extra farewells? Maybe "I'll get you next time!" if CPU lost.
		} else {
			//Playing the game
			if (input == "r" or input == "R") {
				pmove=0;
			} else if (input == "p" or input =="P") {
				pmove=1;
			} else if (input == "s" or input =="S") {
				pmove=2;
			} else {
				std::cout << "Why are you trying to mess up our project?" << std::endl;
				pmove=-1;
			}
			if (pmove!=-1) { //A valid move has been played
				if(algo==1){
					cmove=randomRPS(); //modify this line to use different function
				}
				
				if(algo==2){
					cmove=sequenceRPS(prevmove); //modify this line to use different function
				}
				
				if(algo==3){
					int cutoff=5; //modify cutoff to change length(s) of substrings for pattern matching
					if(movecount<cutoff){
						
						moveseq.append(showrps(pmove));

						//initialize history file
						std::ofstream datafile;
						datafile.open("movehistory.txt", std::ofstream::app);
						datafile << showrps(pmove);
						datafile.close();
						// std::cout << moveseq << std::endl;
						cmove=randomRPS();
					}
					if(movecount>=cutoff){
						
						//////////////////////////////////////////////////////
						// Pattern Selection
						// Runs training function for subsequences of size
						// 1 up to the cutoff
						// Pattern with the highest confidence guess is selected
						//////////////////////////////////////////////////////
						
						double maxp=0;
						int bestmove;
						int pattern;
						
						std::vector< std::pair<int, double> > guessvector;
						
						for(int i=1; i<=cutoff-1; i++){
								std::pair<int, double> guess=trainRPS(moveseq.substr(cutoff-1-i, i), i);
								if(guess.second==1) guess.second=0; //ignore guesses based on only 1 observation
								guessvector.push_back(guess);
								
								if(guess.second>maxp){
									maxp=guess.second;
									bestmove=guess.first;
									pattern=i;
								}
						}	
						
						double pbound=0.5; //probability threshold--ensures algorithm is not too deterministic
						
						//less stringent threshold when player's reaction time is faster than average
						if(time < (0.75*rxnmean)){
							pbound=0.4;
						}
						
						//verify best guess meets probability threshold
						bool inbounds=false;
						for(int j=0; j<guessvector.size(); j++){
							if(inBounds(guessvector[j].second, pbound, 1.0)){
								inbounds=true;
								break;
							}
						}
						
						if(inbounds){
							cmove=bestmove;
							// std::cout << "Matching last " << pattern << " moves. Computer will play: " << showrps(bestmove) << ". Confidence: " << maxp << std::endl;
						} else {
							cmove=randomRPS();
							// std::cout << "Computer lacks confidence. Randomizing guess." << std::endl;
						}
						
						if(lossstreak>3){
							cmove=randomRPS();
							// std::cout << "Lost three in a row...changing strategy" << std::endl;
						}
						
						std::cout << "Computer will play: " << showrps(cmove) << std::endl;
						
						//////////////////////////////////////////////////////
						// After computer move determined, update 
						// and add player move to data file
						//////////////////////////////////////////////////////
						moveseq.append(showrps(pmove));
						moveseq.erase(0,1);
						
						std::ofstream datafile;
						datafile.open("movehistory.txt", std::ofstream::app);
						datafile << showrps(pmove);
						datafile.close();
					}
					
				}
				
				//////////////////////////////////////////////////////
				// Determine winner, update win/loss streak, 
				// and trash talk accordingly
				//////////////////////////////////////////////////////
				
				if (cmove==pmove) {
					wtl[1]++;
					lossstreak=0;
					streak=0;
				} else if (cmove==(pmove+1)%3) {
					wtl[2]++;
					lossstreak=0;
					streak++;
				} else {
					wtl[0]++;
					lossstreak++;
					streak=0;
				}
							
				std::cout << "You played: " << showrps(pmove) << "  CPU played: " << showrps(cmove) << std::endl;
            
				if (streak==3) {std::cout << "Gotta step up your game!" <<std::endl;}
				else if (streak==6) {std::cout << "Get read like a Dr. Seuss book!" <<std::endl;}
				else if (streak==9) {std::cout << "DEEEEEESTRUUUUCTIIOOOOON" <<std::endl;}
            
				std::cout << "Current W-T-L record: " << wtl[0] << "-" << wtl[1] << "-" << wtl[2] << std::endl;
			
				prevmove=pmove;
				movecount++;
			}
		}
	}
	return 0;
}
